#include "factory.h"

int exit_fds[2];
//退出机制信号处理函数
void sig_exit_func(int signum)
{
    write(exit_fds[1],&signum,1);
}

int main(int argc,char** argv)
{
    if(argc!=3)
    {
        printf("/thread_pool_server IP PORT\n");
        return -1;
    }
    pipe(exit_fds);
    if(fork())//父进程用来协助完成退出机制
    {
        close(exit_fds[0]);
        signal(SIGUSR1,sig_exit_func);//将10号信号传给信号处理函数
        wait(NULL);
       return 0;
    }
    close(exit_fds[1]);
    Factory_t f;//主数据结构
    int thread_num=THREAD_NUM;//子线程数量
    int capacity=CAPACITY;//队列容量
    factory_init(&f,thread_num,capacity);//线程池初始化
    factory_start(&f,thread_num);//启动线程池
    int socket_fd;
    tcp_init(&socket_fd,argv[1],argv[2]);
    //接收请求，加锁，放入队列，解锁，signal
    int new_fd;
    struct sockaddr_in client_addr;
    Client_State_t* pnew;
    train_state_t* ct;
    pQue_t pq=&f.que;//让一个队列指针指向队列
    //epoll注册监控socket_fd,exit_fd[0]
    int epfd=epoll_create(1);
    struct epoll_event evs[2];
    epoll_add(epfd,exit_fds[0]);
    epoll_add(epfd,socket_fd);
    int ready_fd_num,i,j,ret;
    usraddr usr;
    char salt[30]={0};
    int salt_len=sizeof(salt);
    int pwdret;
    while(1)
    {
        printf("----\n");
        ready_fd_num=epoll_wait(epfd,evs,2,-1);//等待描述符就绪，哪个描述符就绪，epoll就会返回
        printf("----\n");
        for(i=0;i<ready_fd_num;i++)
        {
            if(evs[i].data.fd==socket_fd)//如果有客户端连接了
            {
                bzero(&client_addr,sizeof(client_addr));//清空
                socklen_t addr_len=sizeof(client_addr);
                printf("----\n");
                new_fd=accept(socket_fd,(struct sockaddr*)&client_addr,&addr_len);
                ERROR_CHECK(new_fd,-1,"accept");
                printf("----\n");
                //epoll_add(epfd,new_fd);
                if(new_fd!=-1)
                {
                    printf("%d Connect success!\n",new_fd);
                }    
                else
                {
                    printf("%d Connect fail!\n",new_fd);
                    continue;
                }
            }
            else if(evs[i].data.fd==new_fd)//如果new_fd可读
            {
                //密码验证
                memset(&usr,0,sizeof(usraddr));
                ret=recv_n(new_fd,&usr.data_len,sizeof(int));//接用户名长度 
                SELFFUNC_ERR_CHECK(ret,"recv_n");
                ret=recv_n(new_fd,&usr.usrA,4+usr.data_len);//接用户名内容
                SELFFUNC_ERR_CHECK(ret,"recv_n");
                printf("%s come!\n",usr.usrA);
                //检查用户名是否正确
                struct spwd *sp;
                sp=getspnam(usr.usrA);
                if((sp=getspnam(usr.usrA))==NULL)
                {
                    error_quit("Obtain the usrname and passwd");
                }
                pwdret=send_n(new_fd,&ret,sizeof(int));//向客户端发送用户名检查情况
                SELFFUNC_ERR_CHECK(ret,"send_n");
                if(pwdret==-1)
                {
                    printf("leave");
                    break;   
                }
                get_salt(salt,sp->sp_pwdp);
                if(!ret)//用户名正确，发送盐值给客户端
                {
                    ret=send_n(new_fd,&salt_len,sizeof(int));//发送盐值长度
                    SELFFUNC_ERR_CHECK(ret,"send_n");
                    ret=send_n(new_fd,salt,4+salt_len);//发送盐值内容
                    SELFFUNC_ERR_CHECK(ret,"send_n");
                    memset(&usr.pwd,0,sizeof(usr.pwd));
                    ret = recv_n(new_fd,&usr.data_len,sizeof(int));//接收客户端发来的加密符号串长度
                    SELFFUNC_ERR_CHECK(ret,"recv_n");
                    ret=recv_n(new_fd,usr.pwd,4+usr.data_len);//接收客户端发来的加密符号串内容
                    SELFFUNC_ERR_CHECK(ret,"recv_n");
                }
                else 
                {
                    printf("Error usrname!\n");
                    continue;
                }
                pwdret=check_pwd(sp->sp_pwdp,usr.pwd);
                ret=send_n(new_fd,&pwdret,sizeof(int));//发送密码验证情况，正确返0
                SELFFUNC_ERR_CHECK(ret,"send_n");
                if(!pwdret)//密码验证通过
                {
                    int data_len;
                    bzero(&ct,sizeof(train_state_t));
                    ret=recv_n(new_fd,&data_len,sizeof(int));//接命令长度
                    SELFFUNC_ERR_CHECK(ret,"recv_n");
                    ret=recv_n(new_fd,&ct,4+data_len);//接命令内容
                    SELFFUNC_ERR_CHECK(ret,"recv_n");
                    ct->cmd_type = cmd_type_func(ct->cmd);
                    if(ct->cmd_type==LS||ct->cmd_type==CD||ct->cmd_type==REMOVE||ct->cmd_type==PWD)
                    {
                        command(ct,pnew);
                    }
                    else{
                        pNode_t pnew = (pNode_t)calloc(1,sizeof(Node_t));
                        bzero(&pnew,sizeof(pNode_t));
                        pnew->rv_cmd=ct;
                        pnew->tran_fd=new_fd;
                        strcpy(pnew->belongID,usr.usrA);
                        pthread_mutex_lock(&pq->mutex);
                        que_set(pq,pnew);//放入队列
                        pthread_mutex_unlock(&pq->mutex);//解锁
                        pthread_cond_signal(&f.cond);//使条件成立
                    }
                }
            }
            if(evs[i].data.fd==exit_fds[0])//线程池要退出了
            {
                for(j=0;j<thread_num;j++)//给每一个子线程发送cancel信号
                {
                    pthread_cancel(f.pthid[j]);
                    printf("thread %d cancel success\n",getpid());
                }
                for(j=0;j<thread_num;j++)//等待每一个子线程
                {
                    pthread_join(f.pthid[j],NULL);
                }
            }
        }
    }
    close(socket_fd);//关闭对应的描述符
    close(new_fd);
    return 0;
}
